package handler

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/wrappers"

	"kop/framework/broker"
	context2 "kop/framework/context"
	"kop/framework/errors"
	"kop/libs/database"
	"kop/modules/achievement/configuration/a_type"
	"kop/modules/quest/configuration"
	_type "kop/modules/quest/configuration/dailyquest/type"
	"kop/modules/quest/configuration/questtype"
	"kop/modules/quest/entity"
	"kop/modules/quest/models"
	"kop/pb"
	"kop/pb/service"

	achievementC "kop/modules/achievement/client"
	awardM "kop/modules/award/models"
	buildingC "kop/modules/building/client"
	captainC "kop/modules/captain/client"
	maidC "kop/modules/maid/client"
	moneyC "kop/modules/money/client"
	roleC "kop/modules/role/client"
	stageC "kop/modules/stage/client"
)

type QuestServiceHandler struct {
	context2.Context
}

func (h *QuestServiceHandler) GetQuest(ctx context.Context, req *service.RoleRequest, resp *pb.Quest) error {

	var quest = models.GetQuest(database.DB, req.RoleID)
	var conf = configuration.GetByQuestID(quest.QuestID)

	switch conf.QuestType {
	case questtype.Login:
	case questtype.RoleLevel:
	case questtype.Stage:
	default:

		h.checkQuest(ctx, &quest, nil)
	}

	*resp = *buildPbQuest(quest)
	return nil
}

func (h *QuestServiceHandler) SetNumber(ctx context.Context, req *service.QuestSetRequest, _ *empty.Empty) error {

	var quest = models.GetQuest(database.DB, req.RoleID)

	var conf = configuration.GetByQuestID(quest.QuestID)
	if conf.QuestType == questtype.QuestType(req.Type) {

		if conf.NeedID > 0 && conf.NeedID != req.NeedID {
			return nil
		}

		quest.Value = req.Number
		models.Save(database.DB, &quest)

		// 推送客户端
		_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeQuest, buildPbQuest(quest))
	}

	return nil
}

func (h *QuestServiceHandler) AddNumber(_ context.Context, req *service.QuestSetRequest, _ *empty.Empty) error {

	var quest = models.GetQuest(database.DB, req.RoleID)

	var conf = configuration.GetByQuestID(quest.QuestID)
	if conf.QuestType == questtype.QuestType(req.Type) {

		if conf.NeedID > 0 && conf.NeedID != req.NeedID {
			return nil
		}

		quest.Value += req.Number
		models.Save(database.DB, &quest)

		_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeQuest, buildPbQuest(quest))
	}

	return nil
}

func (h *QuestServiceHandler) Finish(ctx context.Context, _ *empty.Empty, resp *pb.FinishQuestReply) error {

	var roleID = h.GetRoleID(ctx)

	var quest = models.GetQuest(database.DB, roleID)
	var conf = configuration.GetByQuestID(quest.QuestID)

	if quest.Value < conf.NeedValue {

		return errors.ParamError
	}

	quest.QuestID = conf.NextID
	quest.Value = 0

	models.Save(database.DB, &quest)

	var role = roleC.GetRole(roleID)
	h.checkQuest(ctx, &quest, role)
	//NULL                QuestType = 99

	resp.Quest = buildPbQuest(quest)
	resp.Award = awardM.RandAward(role, conf.AwardID)
	return awardM.SendAward(role, resp.Award)
}

//rpc GetDailyQuests (RoleRequest) returns (DailyQuests) {}
//rpc SaveDailyQuest (DailyQuest) returns (DailyQuest) {}
//rpc DailyQuestAddNumber (DailyQuestAddRequest) returns (Empty) {}

func (h *QuestServiceHandler) GetDailyQuests(ctx context.Context, req *service.RoleRequest, dailyQuests *service.DailyQuests) error {

	dailyQuests.DailyQuests = models.GetDailyQuests(database.DB, req.RoleID)
	if res, err := roleC.RoleService.GetMonthCard(ctx, req); err == nil {
		// 月卡自动完成
		if res.MonthCard.Day > 0 {
			for _, dailyQuest := range dailyQuests.DailyQuests {
				if _type.Type(dailyQuest.Type) == _type.MonthCard && !dailyQuest.Finish {
					dailyQuest.Value += 1
					models.SaveDailyQuest(database.DB, dailyQuest)
				}
			}
		}
		// 年卡自动完成
		if res.YearCard.Day > 0 {
			for _, dailyQuest := range dailyQuests.DailyQuests {
				if _type.Type(dailyQuest.Type) == _type.YearCard && !dailyQuest.Finish {
					dailyQuest.Value += 1
					models.SaveDailyQuest(database.DB, dailyQuest)
				}
			}
		}
	}
	return nil
}

func (h *QuestServiceHandler) SaveDailyQuest(ctx context.Context, req *pb.DailyQuest, dailyQuest *pb.DailyQuest) error {

	*dailyQuest = *req
	models.SaveDailyQuest(database.DB, dailyQuest)
	return nil
}

func (h *QuestServiceHandler) DailyQuestAddNumber(_ context.Context, req *service.DailyQuestAddRequest, _ *empty.Empty) error {

	var dailyQuests = models.GetDailyQuests(database.DB, req.RoleID)
	for _, dailyQuest := range dailyQuests {
		if dailyQuest.Type == req.Type && !dailyQuest.Finish {
			dailyQuest.Value += req.Number

			models.SaveDailyQuest(database.DB, dailyQuest)

			// 推送客户端
			_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeDailyQuest, dailyQuest)
		}
	}
	return nil
}

func (h *QuestServiceHandler) Check(ctx context.Context, req *service.QuestCheckRequest, _ *empty.Empty) error {

	var quest = models.GetQuest(database.DB, req.RoleID)

	var conf = configuration.GetByQuestID(quest.QuestID)
	for _, t := range req.Types {
		if t == int32(conf.QuestType) {

			var old = quest.Value

			h.checkQuest(ctx, &quest, nil)

			if quest.Value != old {
				_ = broker.RolePublish(req.RoleID, pb.WsCode_CodeQuest, buildPbQuest(quest))
			}
			break
		}
	}

	return nil
}

func (h *QuestServiceHandler) checkQuest(ctx context.Context, quest *entity.Quest, role *pb.Role) {

	var oldValue = quest.Value
	var conf = configuration.GetByQuestID(quest.QuestID)

	switch conf.QuestType {
	case questtype.RoleLevel:

		if role == nil {
			role = roleC.GetRole(quest.RoleID)
		}

		quest.Value = int64(role.Level)

	case questtype.Ship:

		var building = buildingC.GetBuilding(quest.RoleID, conf.NeedID)
		if building != nil {
			quest.Value = 1
		}

	case questtype.Sailor:

		var building = buildingC.GetBuilding(quest.RoleID, conf.NeedID)
		if building != nil {
			quest.Value = int64(building.Seaman)
		}

	case questtype.CaptainLevel:

		for _, captain := range captainC.GetCaptains(quest.RoleID) {
			if captain.CaptainID == conf.NeedID {
				quest.Value = int64(captain.Level)
				break
			}
		}

	case questtype.Income:

		quest.Value = moneyC.GetIncome(quest.RoleID)

	case questtype.Power:

		quest.Value = captainC.SumPower(quest.RoleID)

	case questtype.Stage:

		var stage = stageC.GetStage(ctx)
		if stage.StageID > conf.NeedID {
			quest.Value = 1
		}

	case questtype.ShipLevelUp:

		var buildings = buildingC.GetBuildings(quest.RoleID)

		quest.Value = 0
		for _, building := range buildings {
			if building.BuildingID >= 201 && building.BuildingID <= 205 {
				quest.Value += int64(building.Level - 1)
			}
		}

	case questtype.Employ:

		var buildings = buildingC.GetBuildings(quest.RoleID)

		quest.Value = 0
		for _, building := range buildings {
			quest.Value += int64(building.Seaman)
		}

	case questtype.CaptainLevelNum:

		quest.Value = 0
		var captains = captainC.GetCaptains(quest.RoleID)
		for _, v := range captains {
			if v.Level >= conf.NeedID {
				quest.Value += 1
			}
		}

	case questtype.CaptainClass:

		quest.Value = 0
		var captains = captainC.GetCaptains(quest.RoleID)
		for _, v := range captains {
			if v.Class >= conf.NeedID {
				quest.Value += 1
			}
		}

	case questtype.Maid:

		var maids = maidC.GetMaids(quest.RoleID)
		quest.Value = int64(len(maids))

	case questtype.CaptainSkillLevelUp:

		var captains = captainC.GetCaptains(quest.RoleID)

		quest.Value = 0
		for _, captain := range captains {

			quest.Value += int64(captain.Skill2.Level - 1)
			quest.Value += int64(captain.Skill3.Level - 1)
		}

	case questtype.MaidSkillLevelUp:

		var maids = maidC.GetMaids(quest.RoleID)

		quest.Value = 0
		for _, maid := range maids {
			for _, skill := range maid.Skills {
				quest.Value += int64(skill.Level - 1)
			}
		}

	case questtype.Login:

		var res, _ = roleC.RoleService.GetSignIn(ctx, &empty.Empty{})
		quest.Value = int64(res.Number)

	case questtype.Bar:

		if res, err := achievementC.AchievementService.GetAchievement(ctx, &wrappers.Int32Value{Value: int32(a_type.Bar)}); err == nil {
			quest.Value = res.Value
		}

	case questtype.Date:

		if res, err := achievementC.AchievementService.GetAchievement(ctx, &wrappers.Int32Value{Value: int32(a_type.Date)}); err == nil {
			quest.Value = res.Value
		}

	case questtype.Train:

		if res, err := achievementC.AchievementService.GetAchievement(ctx, &wrappers.Int32Value{Value: int32(a_type.Train)}); err == nil {
			quest.Value = res.Value
		}

	case questtype.Event:

		if res, err := achievementC.AchievementService.GetAchievement(ctx, &wrappers.Int32Value{Value: int32(a_type.Event)}); err == nil {
			quest.Value = res.Value
		}

	case questtype.Conquer:

		if res, err := achievementC.AchievementService.GetAchievement(ctx, &wrappers.Int32Value{Value: int32(a_type.Conquer)}); err == nil {
			quest.Value = res.Value
		}

	case questtype.GuildBuild:

		if res, err := achievementC.AchievementService.GetAchievement(ctx, &wrappers.Int32Value{Value: int32(a_type.GuildBuild)}); err == nil {
			quest.Value = res.Value
		}

	}

	if quest.Value != oldValue {
		models.Save(database.DB, quest)
	}
}

func buildPbQuest(q entity.Quest) *pb.Quest {

	var conf = configuration.GetByQuestID(q.QuestID)

	return &pb.Quest{
		QuestID:   q.QuestID,
		Type:      int32(conf.QuestType),
		Value:     q.Value,
		NeedValue: conf.NeedValue,
	}
}
